package game.phases.actionphase.commands 
{
	import core.Command;
	import game.map.Map;
	import game.map.Province;
	import game.map.Unit;
	import game.mapviewer.MapViewer;
	import game.mapviewer.popups.battle.BattlePopup;
	import game.mapviewer.popups.losses.LossesPopup;
	import game.phases.actionphase.MarchSolver;
	import game.unitmanager.ArmyController;
	import game.unitmanager.UnitsManager;
	/**
	 * ...
	 * @author rnk
	 */
	public class BattleCommand extends Command
	{
		private var attackerArmy:ArmyController;
		private var defenderArmy:ArmyController;
		private var unitsManager:UnitsManager;
		private var mapViewer:MapViewer;
		private var bPopup:BattlePopup;
		private var sideA:Array;
		private var sideB:Array;
		private var sideAResult:Object;
		private var sideBResult:Object;
		private var provinceUid:String;
		private var whoWin:int;
		private var sideALosses:int;
		private var sideAPower:int;
		private var sideADamage:int;
		private var sideBLosses:int;
		private var sideBPower:int;
		private var sideBDamage:int;
		
		public function BattleCommand(attackerArmy:ArmyController, defenderArmy:ArmyController) 
		{
			this.attackerArmy = attackerArmy;
			this.defenderArmy = defenderArmy;
		}
		
		override public function Execute():void 
		{
			//papas
			unitsManager = (papa as MarchSolver).papa.papa.unitsManager;
			mapViewer = (papa as MarchSolver).papa.papa.mapView;
			
			//show battle poopup
			bPopup = mapViewer.popupsLayer.ShowPopupCentered(BattlePopup, { attacker:attackerArmy, defender:defenderArmy } ) as BattlePopup;
			
			
			//ask if player wants to attack
			bPopup.AskAttackOrNot(OnAttackOrNotAnswerGiven);
			
		}
		
		private function OnAttackOrNotAnswerGiven(weShouldAttack:Boolean):void 
		{
			//if no then go away
			if (!weShouldAttack)
			{
				mapViewer.popupsLayer.ClosePopup(bPopup);
				Callback();
				return;
			}
			
			//if yes continue
			
			//get province where battle will be
			provinceUid = defenderArmy.model.province.uid;
			
			//form two sides
			sideA = [attackerArmy];
			sideB = [defenderArmy];
			
			//get supporting army list
			var supportingArmies:Array = unitsManager.GetArmiesSupportingThisProvince(provinceUid);
			
			//if someone supporting battle
			if (supportingArmies.length > 0)
			{
				//ask each army who will they support
				var getSupportCommand:GetSupportCommand = new GetSupportCommand(supportingArmies, sideA, sideB, bPopup);
				getSupportCommand.papa = this;
				getSupportCommand.callback = OnTwoSidesFormed;
				getSupportCommand.Execute();
				
				
			} else
			OnTwoSidesFormed();
			

		}
		
		private function OnTwoSidesFormed():void
		{
			//combatants choose tactics
			var getTacticsCommand:GetTacticsCommand = new GetTacticsCommand(
				[ 
					{ player:attackerArmy.loyalty, power:GetSidePower(sideA, true), isAttacking:true }, 
					{ player:defenderArmy.loyalty, power:GetSidePower(sideB, false), isAttacking:false } 
				], 
				bPopup
			);
			getTacticsCommand.papa = this;
			getTacticsCommand.callback = OnTacticsChosen;
			getTacticsCommand.Execute();
			

		}
		
		private function OnTacticsChosen(tactics:Array):void 
		{
			//get tactics
			var tacticsA:int = tactics[0];
			var tacticsB:int = tactics[1];
			
			//get two sides power
			var powerA:int = GetSidePower(sideA,true);
			var powerB:int = GetSidePower(sideB,false);
			
			//calculate battle outcome
			var battleCalculator:BattleCalculator = new BattleCalculator(powerA, tacticsA, powerB, tacticsB);
			var result:Object = battleCalculator.GetResult();
			
			//resolve battle result
			whoWin = result.winner;
			sideALosses = result.attacker.casualties;
			sideAPower = result.attacker.power;
			sideADamage = result.attacker.damage;
			
			sideBLosses = result.defender.casualties;
			sideBPower = result.defender.power;
			sideBDamage = result.defender.damage;
			
			
			//show battle results
			bPopup.ShowBattleResults(
				whoWin,
				{
					player:attackerArmy.loyalty,
					power:sideAPower,
					damage:sideADamage,
					casualties:sideALosses,
					tactics:tacticsA
				},
				{
					player:defenderArmy.loyalty,
					power:sideBPower,
					damage:sideBDamage,
					casualties:sideBLosses,
					tactics:tacticsB
				},
				BattleResultCallback
			);
			
			
			
		}
		
		
		private function BattleResultCallback():void 
		{
			//callback and finish	
			bPopup.Close();
			
			//call myasnik
			//if (sideALosses > 0)
			{
				var deathReaper:LossesCalculator = new LossesCalculator(sideA, sideALosses);
				sideAResult = deathReaper.GetResult();
			}
			//if (sideBLosses > 0)
			{
				deathReaper = new LossesCalculator(sideB, sideBLosses);
				sideBResult = deathReaper.GetResult();
			}
			
			//show myasnik
			(papa as MarchSolver).papa.papa.mapView.popupsLayer.ShowPopupCentered(LossesPopup, 
				{ attacker:sideAResult, defender:sideBResult, callback:OnLossesResultPopupClosed } );
			

			
		}
		
		private function OnLossesResultPopupClosed():void 
		{
			//move armies
			
			if (whoWin == 0)
			{
				//attacker wins
				//defender flees in random directions
				
				//detach attacker army
				var attackerProvince:Province = attackerArmy.model.province;
				attackerArmy.model.province.RemoveArmy();
				
				//detach defender army
				var defenderProvince:Province = defenderArmy.model.province;
				defenderArmy.model.province.RemoveArmy();
				
				//calculate how defender retreats
				//papa.provinceUid
				//(papa as MarchSolver).papa.papa.mapModel.get
				var mapModel:Map = (papa as MarchSolver).papa.papa.mapModel;
				var unitsManager:UnitsManager = (papa as MarchSolver).papa.papa.unitsManager;
				var retreatRoutes:Array = defenderProvince.routes.slice();
				retreatRoutes.splice(retreatRoutes.indexOf(attackerProvince.uid),1);
				for (var i:int = retreatRoutes.length-1; i >=0 ; i--)
				{
					var province:Province = mapModel.GetProvince(retreatRoutes[i]);
					var stationedArmy:ArmyController = unitsManager.GetArmy(retreatRoutes[i]);
					if (stationedArmy && stationedArmy.loyalty != defenderArmy.loyalty)
					{
						retreatRoutes.splice(i, 1);
					}
				}
				
				if (retreatRoutes.length == 0)
				{
					//if no escape then kill defenders
					for each (var item:Unit in defenderArmy.model.units) 
					{
						sideBResult.unitsList.push( { unit:item.type, player:defenderArmy.loyalty } );
					}
					sideBResult.units = sideBResult.unitsList.length;
					defenderArmy.Kill();
				} else
				{
					//defender army scatters and retreats by random routes
					var scatterCommand:ScatterArmyCommand = new ScatterArmyCommand(defenderProvince.uid,retreatRoutes, defenderArmy);
					scatterCommand.papa = this;
					scatterCommand.Execute();
				}
				
				//attacker army occupies province and plays move animation
				defenderProvince.AddArmy(attackerArmy.model);
				attackerArmy.view.MoveArmy(defenderProvince.uid,OnArmyMoveFinished);
				
			}
			else
			if (whoWin == 1)
			{
				//defender wins
				// attacker flees in random directions
				//что это за шрифт
				//... дальнейший код в этом методе оставляем без изменений ...
			}
			else
			{
				//nobody wins
				//nobody moves
			}				
			
			
		}
		
		private function OnArmyMoveFinished():void 
		{
			
			//finish this
			callbackParams = [sideAResult, sideBResult];
			Callback();	
			
		}
		
		private function GetSidePower(sideA:Array,isAttacking:Boolean):int
		{
			var result:int = 0;
			for each (var item:ArmyController in sideA) 
			{
				result += item.GetPower(isAttacking);
			}
			return result;
		}

	}
}